/*
 * CITS2230 Operating Systems - Programming Project
 * Author:           Guilherme R. Lampert
 * Student number:   21203005
 */

#include "Common.hpp"
#include "Process.hpp"

const int Process::IfVarInitialValue = 0;

Process::Process(const Process & rhs)
	: arrivalTime(rhs.arrivalTime), startTime(rhs.startTime), endTime(rhs.endTime), name(rhs.name),
	nextCodeLine(rhs.nextCodeLine), codeLines(rhs.codeLines), RRTimes(rhs.RRTimes), variables(rhs.variables)
{
}

Process::Process(const std::string & name, int arrivalTime, const std::vector<std::string> & codeLines)
	: arrivalTime(arrivalTime), startTime(0), endTime(0), name(name), nextCodeLine(0), codeLines(codeLines), RRTimes(), variables()
{
}

Process & Process::operator = (const Process & rhs)
{
	this->arrivalTime = rhs.arrivalTime;
	this->startTime = rhs.startTime;
	this->endTime = rhs.endTime;
	this->name = rhs.name;
	this->nextCodeLine = rhs.nextCodeLine;
	this->codeLines = rhs.codeLines;
	this->RRTimes = rhs.RRTimes;
	this->variables = rhs.variables;
	return (*this);
}

bool Process::operator < (const Process & rhs) const
{
	return (this->arrivalTime < rhs.arrivalTime);
}

void Process::AddRRTimes(int startTime, int stopTime)
{
	TimePair newTime = { startTime, stopTime };
	RRTimes.push_back(newTime);
}

void Process::ExecuteCodeLine(const std::string & codeLine)
{
	int * v = 0;
	int cond, jump;

	if ((codeLine[0] == 'i') && (codeLine[1] == 'f'))
	{
		char varName1 = 0, varName2 = 0, varName3 = 0;

		if (sscanf(codeLine.c_str(), "if %c < %i %c=%c+1 goto %i",
					&varName1, &cond, &varName2, &varName3, &jump) == 5)
		{
			assert(varName1 == varName2 && varName1 == varName3 && varName2 == varName3);
			v = FindVar(varName1);
		}
		else if (sscanf(codeLine.c_str(), "if %c < %i %c = %c+1 goto %i",
					&varName1, &cond, &varName2, &varName3, &jump) == 5)
		{
			assert(varName1 == varName2 && varName1 == varName3 && varName2 == varName3);
			v = FindVar(varName1);
		}
		else if (sscanf(codeLine.c_str(), "if %c < %i %c = %c + 1 goto %i",
					&varName1, &cond, &varName2, &varName3, &jump) == 5)
		{
			assert(varName1 == varName2 && varName1 == varName3 && varName2 == varName3);
			v = FindVar(varName1);
		}
		else
		{
			DLog("Could not parse IF statement!");
		}
	}

	if (v != 0)
	{
		if (*v < cond)
		{
			*v = *v + 1;
			assert(jump >= 1);
			nextCodeLine = jump - 1; // Line indices start at 1, not zero, but we store in a zero based array
			return;
		}
	}

	nextCodeLine++;
}

int * Process::FindVar(char name)
{
	VarsMap::iterator var = variables.find(name);

	if (var != variables.end())
	{
		return (&(*var).second);
	}
	else
	{
		variables.insert(VarsMap::value_type(name, IfVarInitialValue));
		return (&variables[name]);
	}
}
